#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>

#define RGB565(r, g, b) ((((r)>>3)<<11) | (((g)>>2)<<5) | ((b)>>3))

int main() {
    int fbfd = 0;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    char *fbp = 0;
    long int screensize = 0;
    uint16_t *fbp16;

    // 打开framebuffer设备fb1
    fbfd = open("/dev/fb1", O_RDWR);
    if (fbfd == -1) {
        perror("Error: cannot open framebuffer device /dev/fb1");
        printf("Trying to open /dev/fb0 instead...\n");
        fbfd = open("/dev/fb0", O_RDWR);
        if (fbfd == -1) {
            perror("Error: cannot open framebuffer device /dev/fb0");
            return -1;
        }
        printf("Successfully opened /dev/fb0\n");
    } else {
        printf("Successfully opened /dev/fb1\n");
    }
    
    printf("The framebuffer device was opened successfully.\n");

    // 获取屏幕固定信息
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        perror("Error reading fixed information");
        close(fbfd);
        return -1;
    }

    // 获取屏幕可变信息
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        perror("Error reading variable information");
        close(fbfd);
        return -1;
    }

    printf("Screen: %dx%d, %d bpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
    printf("Screen memory start: 0x%lx\n", (unsigned long)finfo.smem_start);
    printf("Screen memory length: %d bytes\n", finfo.smem_len);

    // 计算屏幕大小
    screensize = finfo.smem_len;

    // 映射framebuffer到内存
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if (fbp == MAP_FAILED) {
        perror("Error: failed to map framebuffer device to memory");
        close(fbfd);
        return -1;
    }
    printf("The framebuffer device was mapped to memory successfully.\n");
    
    // 将字符指针转换为16位指针，方便操作RGB565像素
    fbp16 = (uint16_t*)fbp;
    int width = vinfo.xres;
    int height = vinfo.yres;

    // 清屏为黑色
    memset(fbp, 0, screensize);
    printf("Screen cleared to black\n");
    sleep(2);

    // 填充红色
    for (int i = 0; i < screensize/2; i++) {
        fbp16[i] = RGB565(255, 0, 0);  // 红色
    }
    printf("Screen filled with red\n");
    sleep(2);

    // 填充绿色
    for (int i = 0; i < screensize/2; i++) {
        fbp16[i] = RGB565(0, 255, 0);  // 绿色
    }
    printf("Screen filled with green\n");
    sleep(2);

    // 填充蓝色
    for (int i = 0; i < screensize/2; i++) {
        fbp16[i] = RGB565(0, 0, 255);  // 蓝色
    }
    printf("Screen filled with blue\n");
    sleep(2);

    // 绘制一个简单的图案 - 对角线
    memset(fbp, 0, screensize);  // 先清屏为黑色
    
    // 绘制对角线
    for (int i = 0; i < width && i < height; i++) {
        fbp16[i * width + i] = RGB565(255, 255, 255);  // 白色点
    }
    
    // 绘制反向对角线
    for (int i = 0; i < width && i < height; i++) {
        fbp16[i * width + (width - 1 - i)] = RGB565(255, 255, 0);  // 黄色点
    }
    
    printf("Diagonal lines drawn\n");
    sleep(3);

    // 绘制简单的色块
    memset(fbp, 0, screensize);  // 先清屏为黑色
    
    // 左上角红色方块
    for (int y = 0; y < height/2; y++) {
        for (int x = 0; x < width/2; x++) {
            fbp16[y * width + x] = RGB565(255, 0, 0);  // 红色
        }
    }
    
    // 右上角绿色方块
    for (int y = 0; y < height/2; y++) {
        for (int x = width/2; x < width; x++) {
            fbp16[y * width + x] = RGB565(0, 255, 0);  // 绿色
        }
    }
    
    // 左下角蓝色方块
    for (int y = height/2; y < height; y++) {
        for (int x = 0; x < width/2; x++) {
            fbp16[y * width + x] = RGB565(0, 0, 255);  // 蓝色
        }
    }
    
    // 右下角白色方块
    for (int y = height/2; y < height; y++) {
        for (int x = width/2; x < width; x++) {
            fbp16[y * width + x] = RGB565(255, 255, 255);  // 白色
        }
    }
    
    printf("Color blocks drawn\n");
    sleep(3);

    // 取消内存映射并关闭设备
    munmap(fbp, screensize);
    close(fbfd);
    
    printf("Framebuffer memory mapping test completed\n");
    return 0;
}
